简化路径

以 Unix 风格给出一个文件的绝对路径,你需要简化它。或者换句话说,将其转换为规范路径。

在 Unix 风格的文件系统中,一个点(.)表示当前目录本身;此外,两个点 (..) 表示将目录切换到上一级(指向父目录);两者都可以是复杂相对路径的组成部分。

请注意,返回的规范路径必须始终以斜杠 / 开头,并且两个目录名之间必须只有一个斜杠 /。最后一个目录名(如果存在)不能以 / 结尾。此外,规范路径必须是表示绝对路径的最短字符串。

示例 1:

1
2
3
输入:"/home/"
输出:"/home"
解释:注意,最后一个目录名后面没有斜杠。

示例 2:

1
2
3
输入:"/../"
输出:"/"
解释:从根目录向上一级是不可行的,因为根是你可以到达的最高级。

示例 3:

1
2
3
输入:"/home//foo/"
输出:"/home/foo"
解释:在规范路径中,多个连续斜杠需要用一个斜杠替换。

示例 4:

1
2
输入:"/a/./b/../../c/"
输出:"/c"

示例 5:

1
2
输入:"/a/../../b/../c//.//"
输出:"/c"

示例 6:

1
2
输入:"/a//b////c/d//././/.."
输出:"/a/b/c"

新的收获:

  1. Stack类的foreach写法居然是从栈底开始遍历的,并不是从栈顶往下走的,查看源码发现Stack继承Vector类,内部为一个数组,故使用foreach语句时被当做了一个数组来遍历。
  2. foreach写法确实是语法糖,但是在性能上,foreach居然要比for i++的写法要慢。
  3. 有点意料之外,根据第3 4次提交foreach居然执行效率还快一些,有可能是因为两个foreach遍历的都是一系数组,看网上有一些说,foreach在遍历链表时会慢很多。(也有可能只是偶然,我没有跑很多次对比)。
  4. replaceAll等、split这种复合运算的,都需要遍历整个数组,对时间的影响比较大,不能因为方便就用。

    代码:

    第一次提交(11%时)

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    class Solution {
    public String simplifyPath(String path) {
    if(path==null||path.length()==0)return null;
    Stack<String> stack=new Stack<>();
    String[] strs=path.replaceAll("/+","/").split("/");
    for(String v:strs)
    {
    if(v.length()==0||v.equals("."))
    continue;
    if(v.equals(".."))
    {
    //一个是顶部没东西
    if(stack.isEmpty())
    continue;
    //一个是顶部还有东西,取出
    else {
    stack.pop();
    }
    }else{
    stack.add(v);
    }
    }
    StringBuffer sb=new StringBuffer();
    //如果没有东西,直接返回根目录就可以了
    if(stack.empty())return "/";
    //这里发现了个新的知识点呀,Stack类的foreach写法居然是从栈底开始遍历的,并不是从栈顶往下走的
    //查看源码发现Stack继承Vector类,内部为一个数组,故使用foreach语句时被当做了一个数组来遍历。
    for(String v:stack)
    {
    sb.append('/');
    sb.append(v);
    //sb.insert(0,v);
    }
    return sb.toString();
    }

    }

第二次提交(修改了foreach写法,发现提升不大,而且空间排少的代码也有使用foreach的):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public String simplifyPath(String path) {
if(path==null||path.length()==0)return null;
Stack<String> stack=new Stack<>();
String[] strs=path.replaceAll("/+","/").split("/");
for(int i=0;i< strs.length;i++)
{
if(strs[i].length()==0||strs[i].equals("."))
continue;
if(strs[i].equals(".."))
{
//一个是顶部没东西
if(stack.isEmpty())
continue;
//一个是顶部还有东西,取出
else {
stack.pop();
}
}else{
stack.push(strs[i]);
}
}
StringBuffer sb=new StringBuffer();
//如果没有东西,直接返回根目录就可以了
if(stack.empty())return "/";
for(int i=0;i<stack.size();i++)
{
sb.append('/');
sb.append(stack.get(i));
//sb.insert(0,v);
}
return sb.toString();
}

}

第三次提交(73%时,97%空):

状态:通过
执行用时: 6 ms
内存消耗: 38.6 MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
public String simplifyPath(String path) {
if(path==null||path.length()==0)return null;
Stack<String> stack=new Stack<>();
String[] strs=path.split("/");
for(int i=0;i< strs.length;i++)
{
if(strs[i].length()==0||strs[i].equals("."))
continue;
if(strs[i].equals(".."))
{
//一个是顶部没东西
if(stack.isEmpty())
continue;
//一个是顶部还有东西,取出
else {
stack.pop();
}
}else{
stack.push(strs[i]);
}
}

//如果没有东西,直接返回根目录就可以了
if(stack.empty())return "/";
StringBuffer sb=new StringBuffer();
for(int i=0;i<stack.size();i++)
{
sb.append('/');
sb.append(stack.get(i));
//sb.insert(0,v);
}
return sb.toString();
}

}

在第三次基础上改回foreach,看一下时空的影响(91%时,88%空):

执行用时: 5 ms
内存消耗: 38.7 MB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
class Solution {
public String simplifyPath(String path) {
if(path==null||path.length()==0)return null;
Stack<String> stack=new Stack<>();
String[] strs=path.split("/");
for(String v:strs)
{
if(v.length()==0||v.equals("."))
continue;
if(v.equals(".."))
{
//一个是顶部没东西
if(stack.isEmpty())
continue;
//一个是顶部还有东西,取出
else {
stack.pop();
}
}else{
stack.add(v);
}
}

//如果没有东西,直接返回根目录就可以了
if(stack.empty())return "/";
StringBuffer sb=new StringBuffer();
for(String v:stack)
{
sb.append('/');
sb.append(v);
}
return sb.toString();
}

}